package sudoku;

import java.util.*;

public class SudokuModel {
    private final int[][] answerGrid; // 存储未挖洞的数独解答
    private final int[][] userGrid;    // 存储挖洞后的题目，并记录用户填写的数字
    private final boolean[][] lightGrid; // 标记与 selectCell相同行、列的格子，以及在一个区域的格子
    private final boolean[][] sameNumGrid; // 标记与 selectCell 数字相同的单元格
    private int selectedRow ,selectedCol;
    private boolean badMove = false;
    private int[] numCount ; // 用于记录每个数字出现的次数

    public SudokuModel() {
        answerGrid = new int[9][9];
        userGrid = new int[9][9];
        lightGrid = new boolean[9][9];
        sameNumGrid = new boolean[9][9];
        numCount = new int[9];
        generatePuzzle(30); // 初级难度，挖30个洞
    }

    public void setBadMove(boolean badMove) {
        this.badMove = badMove;
    }

    public boolean getBadMove() {
        return this.badMove;
    }

    public int[] getNumberCount() {
        return numCount;
    }

    public void selectCell(int row, int col) {
        selectedRow = row;
        selectedCol = col;
        markGrid(row, col);
    }

    private void markGrid(int row, int col)  {
        // 标记高亮的格子
        {
            // 重置 lightGrid
            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {
                    lightGrid[i][j] = false;
                }
            }
            // 高亮整行
            for (int i = 0; i < 9; i++) {
                lightGrid[row][i] = true;
            }

            // 高亮整列
            for (int i = 0; i < 9; i++) {
                lightGrid[i][col] = true;
            }

            // 高亮所在的 3x3 宫格
            int startRow = row - row % 3;
            int startCol = col - col % 3;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    lightGrid[startRow + i][startCol + j] = true;
                }
            }
        }

        // 标记相同数字的格子
        {
            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {
                    sameNumGrid[i][j] = false;
                }
            }
            int s = userGrid[selectedRow][selectedCol];
            if (s != 0) {
                for (int i = 0; i < 9; i++) {
                    for (int j = 0; j < 9; j++) {
                        if (userGrid[i][j] == s) {
                            sameNumGrid[i][j] = true;
                        }
                    }
                }
            }
            sameNumGrid[selectedRow][selectedCol] = true;
        }
    }

    // 新增 printGrid 函数，用于打印 lightGrid 的内容
    private void printGrid(int[][] grid) {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                System.out.print(grid[i][j] > 0 ? grid[i][j] + " " : ". ");
                if (j == 2 || j == 5) {
                    System.out.print("| ");
                }
            }
            System.out.println();
            if (i == 2 || i == 5) {
                System.out.println("------+-------+------");
            }
        }
        System.out.println();
    }

    public int getSelectedRow() {
        return selectedRow;
    }

    public int getSelectedCol() {
        return selectedCol;
    }

    public boolean[][] getLightGrid() {
        return lightGrid;
    }

    public boolean[][] getSameNumGrid() {
        return sameNumGrid;
    }

    // 使用回溯算法生成终盘
    private boolean generateAnswerGrid() {
        badMove = false;
        numCount = new int[9];
        for (int[] g : answerGrid) Arrays.fill(g, 0);
        for (boolean[] g : lightGrid) Arrays.fill(g, false);
        for (boolean[] g : sameNumGrid) Arrays.fill(g, false);
        // 初始化随机数生成器
        Random random = new Random();
        // 生成一个随机的数字列表
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Collections.shuffle(numbers, random);

        boolean success = solve(answerGrid, numbers);
        if (success && !isValidSudoku(answerGrid)) {
            // 如果生成的终盘不符合规则，重新生成
            return generateAnswerGrid();
        }
        return success;
    }

    private boolean solve(int[][] grid, List<Integer> numbers) {
        int[] nextCell = findNextEmptyCell(grid);
        int row = nextCell[0];
        int col = nextCell[1];

        // 如果没有空单元格，说明数独已经解决
        if (row == -1 && col == -1) {
            return true;
        }

        // 尝试填充数字
        for (int num : numbers) {
            if (isValidMove(grid, row, col, num)) {
                grid[row][col] = num;
                if (solve(grid, numbers)) {
                    return true;
                }
                grid[row][col] = 0; // 回溯
            }
        }
        return false;
    }

    // 找到下一个空单元格，优先选择候选数最少的单元格
    private int[] findNextEmptyCell(int[][] grid) {
        int[] bestCell = {-1, -1};
        int minCandidates = Integer.MAX_VALUE;

        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                if (grid[row][col] == 0) {
                    int numCandidates = countCandidates(grid, row, col);
                    if (numCandidates < minCandidates) {
                        minCandidates = numCandidates;
                        bestCell[0] = row;
                        bestCell[1] = col;
                    }
                }
            }
        }
        return bestCell;
    }

    // 计算当前单元格的候选数数量
    private int countCandidates(int[][] grid, int row, int col) {
        int count = 0;
        for (int num = 1; num <= 9; num++) {
            if (isValidMove(grid, row, col, num)) {
                count++;
            }
        }
        return count;
    }

    // 验证整个数独网格是否符合规则
    private boolean isValidSudoku(int[][] grid) {
        int[][] tempGrid = new int[9][9];
        copyGrid(grid, tempGrid); // 使用临时副本避免修改原网格
        for (int row = 0; row < 9; row++) {
            for (int col = 0; col < 9; col++) {
                int num = tempGrid[row][col];
                if (num != 0) {
                    tempGrid[row][col] = 0;
                    if (!isValidMove(tempGrid, row, col, num)) {
                        return false;
                    }
                    tempGrid[row][col] = num;
                }
            }
        }
        return true;
    }

    public void makeMove(int row, int col, int num) {
        if (row < 0 || row >= 9 || col < 0 || col >= 9) {
            return;
        }
        userGrid[row][col] = num; // 修改用户填写的网格

        numCount = new int[9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                int x = userGrid[i][j];
                if ( x > 0 && x <= 9) {
                    numCount[x-1]++;
                }
            }
        }

        markGrid(row, col);
        printGrid(userGrid);
    }

    public boolean isRightAnswer(int row, int col, int num) {
        // 增加边界检查
        if (row < 0 || row >= 9 || col < 0 || col >= 9) {
            return false;
        }
        // 检查当前单元格是否为空
        if (userGrid[row][col] != 0) {
            return false;
        }
        // 直接与 answerGrid 中的数据做对比
        return (answerGrid[row][col] == num);
    }

    // 检查在指定位置放置数字是否有效
    private boolean isValidMove(int[][] grid, int row, int col, int num) {
        // 检查行是否有重复
        for (int i = 0; i < 9; i++) {
            if (grid[row][i] == num) {
                return false;
            }
        }
        // 检查列是否有重复
        for (int i = 0; i < 9; i++) {
            if (grid[i][col] == num) {
                return false;
            }
        }
        // 检查3x3宫格是否有重复
        int startRow = row - row % 3;
        int startCol = col - col % 3;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (grid[startRow + i][startCol + j] == num) {
                    return false;
                }
            }
        }
        return true;
    }

    // 使用挖洞算法生成题目，并确保有唯一解
    public void generatePuzzle(int holes) {
        generateAnswerGrid();
        copyGrid(answerGrid, userGrid);
        Random random = new Random();

        int created = 0;
        int attempts = 0;
        final int maxAttempts = holes * 100; // 最大尝试次数为需求洞数的100倍

        while (created < holes && attempts < maxAttempts) {
            int row = random.nextInt(9);
            int col = random.nextInt(9);
            attempts++; // 每次尝试都计数

            if (userGrid[row][col] == 0) continue;

            int backupValue = userGrid[row][col];
            userGrid[row][col] = 0;

            int[][] snapshot = new int[9][9];
            copyGrid(userGrid, snapshot);
            if (hasUniqueSolution(snapshot) && isSolvableByLogic(snapshot)) {
                created++;
                System.out.println("挖洞成功: (" + row + ", " + col + ")");
            } else {
                userGrid[row][col] = backupValue;
            }
        }

        printGrid(userGrid);
        printGrid(answerGrid);
        if (created < holes) {
            System.out.println("警告：仅生成 " + created + "/" + holes + " 个洞");
        }
    }

    // 新增方法：检查数独是否可以通过逻辑推理解决
    private boolean isSolvableByLogic(int[][] grid) {
        int[][] tempGrid = new int[9][9];
        copyGrid(grid, tempGrid); // 假设 copyGrid 正确复制二维数组

        boolean hasUpdate;
        do {
            hasUpdate = false;
            for (int row = 0; row < 9; row++) {
                for (int col = 0; col < 9; col++) {
                    if (tempGrid[row][col] != 0) continue;

                    int candidate = 0;
                    int candidateCount = 0;

                    // 检查当前单元格的所有可能值
                    for (int num = 1; num <= 9 && candidateCount <= 1; num++) {
                        if (isValidMove(tempGrid, row, col, num)) {
                            candidate = num;
                            candidateCount++;
                        }
                    }

                    // 根据候选值数量处理
                    if (candidateCount == 1) {
                        tempGrid[row][col] = candidate;
                        hasUpdate = true;
                    } else if (candidateCount == 0) {
                        return false; // 无解
                    }
                }
            }
        } while (hasUpdate);
        return true; // 所有空位无法继续推断，但可能未完全填满
    }

    // 检查数独是否有唯一解
    private boolean hasUniqueSolution(int[][] grid) {
        int[][] tempGrid = new int[9][9];
        copyGrid(grid, tempGrid);
        int solutions = countSolutions(tempGrid, 0, 0);
        System.out.println("当前数独的解的数量: " + solutions);
        return solutions == 1;
    }

    // 计算数独的解的数量
    private int countSolutions(int[][] grid, int row, int col) {
        if (row == 9) {
            return 1;
        }
        if (col == 9) {
            return countSolutions(grid, row + 1, 0);
        }
        if (grid[row][col] != 0) {
            return countSolutions(grid, row, col + 1);
        }

        int count = 0;
        for (int num = 1; num <= 9; num++) {
            if (isValidMove(grid, row, col, num)) {
                grid[row][col] = num;
                count += countSolutions(grid, row, col + 1);
                if (count > 1) {
                    break; // 如果找到多个解，提前退出
                }
                grid[row][col] = 0;
            }
        }
        return count;
    }

    // 复制数独网格
    private void copyGrid(int[][] src, int[][] dest) {
        for (int i = 0; i < 9; i++) {
            System.arraycopy(src[i], 0, dest[i], 0, 9);
        }
    }

    public int[][] getUserGrid() {
        return userGrid;
    }

    public boolean isSolved() {
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                if (userGrid[i][j] == 0) {
                    return false;
                }
            }
        }
        return true;
    }
}